package com.nuoniu.sibanyun.service.erp.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.nuoniu.sibanyun.common.exception.NuoNiuException;
import com.nuoniu.sibanyun.common.lang.StringUtils;
import com.nuoniu.sibanyun.common.text.PinyinUtils;
import com.nuoniu.sibanyun.entity.bo.*;
import com.nuoniu.sibanyun.entity.dto.*;
import com.nuoniu.sibanyun.entity.erp.ErpVoucherDesign;
import com.nuoniu.sibanyun.entity.erp.ErpVoucherTable;
import com.nuoniu.sibanyun.entity.erp.ErpVoucherType;
import com.nuoniu.sibanyun.entity.erp.barcode.ErpBarcodeMainInfo;
import com.nuoniu.sibanyun.entity.production.VProductionWorkInventoryDetail;
import com.nuoniu.sibanyun.entity.production.VProductionWorkProcedureDetail;
import com.nuoniu.sibanyun.entity.vo.VProductionWorkDetailSimpleVo;
import com.nuoniu.sibanyun.entity.vo.VProductionWorkProcedureDetailVo;
import com.nuoniu.sibanyun.entity.vo.VoucherReferenceVo;
import com.nuoniu.sibanyun.mapper.erp.ErpVoucherDesignMapper;
import com.nuoniu.sibanyun.service.erp.IErpAccountService;
import com.nuoniu.sibanyun.service.erp.IErpVoucherDesignService;
import com.nuoniu.sibanyun.service.erp.IErpVoucherReferencePropertieService;
import com.nuoniu.sibanyun.service.erp.IErpVoucherTableService;
import com.nuoniu.sibanyun.service.erp.in.IInWarehouseService;
import com.nuoniu.sibanyun.service.production.IVProductionWorkDetailService;
import com.nuoniu.sibanyun.userThread.DataScope;
import com.nuoniu.sibanyun.userThread.UserInfo;
import com.nuoniu.sibanyun.userThread.UserThreadLocal;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.http.ResponseEntity;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;

import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 单据设计 服务实现类
 * </p>
 *
 * @author baiqiang
 * @since 2020-09-23
 */
@Log4j2
@Service
public class ErpVoucherDesignServiceImpl extends ServiceImpl<ErpVoucherDesignMapper, ErpVoucherDesign> implements IErpVoucherDesignService {

    /** 校验 数字 用逗号 隔开 的字符串 */
    public static final String STR_ENG_PATTERN="^\\d+(,\\d+)*$";
    //采购业务单据(包含退货业务)
    private static final  String[] PuVoucherCodesArr
            = {"PuArrival","PurchaseInvoice","PurchaseReceiveVoucher"};
    //入库业务单据（仓库数据权限）
    private static final  String[] ReceiveVoucherArr
            = {"PurchaseReceiveVoucher","ProductReceiveVoucher","OtherReceiveVoucher","DelegateReceiveVoucher","Contract"};
    //销售业务单据(包含退货业务)
    private static final  String[] SaVoucherCodesArr
            = {"SaleDispatchVoucher","SaleDelivery","SaleInvoice"};
    //出库业务单据（仓库数据权限）
    private static final  String[] DispatchVoucherArr = {"DelegateDispatchVoucher","SaleDispatchVoucher","MaterialDispatchVoucher","OtherDispatchVoucher"};
    //只查询 自己管理仓库的数据 的单据
    private static final String[] isMyWarehouseVoucherArr = {"RRS","DelegateRRS"};
    //来源单据状态为2（提交申请），才可以生单
    private static final String[] applyVoucherArr = {"RRS","DelegateRRS"};
    //退货 业务类型
    private static final Integer[] retBusinessTypeArr = {31,32,96,97,98,99};
    //不能再生单 的单据类型
    private static final Integer[] noNextVoucherBusinessTypeArr = {31,96,97};
    //第三层 明细
    private static final  String[] moreDetailVoucherArr
            = {"ProductionWork","DelegateProductionWork"};

    /** 出入库 单据 实际收发 数量 */


    @Autowired
    private IErpVoucherReferencePropertieService erpVoucherReferencePropertieService;
    @Autowired
    private IErpAccountService erpAccountService;
    @Autowired
    private IErpVoucherTableService erpVoucherTableService;
    @Autowired
    private IInWarehouseService iInWarehouseService;
    @Autowired
    @Lazy
    private IVProductionWorkDetailService productionWorkDetailService;

    @Override
    public Page<HashMap<String, Object>> voucherDynamicPage(DynamicVoucherDto dynamicVoucherDto) {
        UserInfo userInfo = UserThreadLocal.get();
        DataScope dataScope = userInfo.getDataScope();
        Integer type = dataScope.getType();
        Integer currentAccountId = erpAccountService.getCurrentAccountId();
        Boolean isSearchDetail = dynamicVoucherDto.getIsSearchDetail();
        //1.解析 动态参数,获取对应表关系
        List<ErpVoucherDesignSearchDto> designSearchDtos = dynamicVoucherDto.getDesignSearchDtos();
        if(null == designSearchDtos || 0 == designSearchDtos.size())throw new NuoNiuException("请传递参数");
        ErpVoucherDesignSearchDto erpVoucherDesignSearchDto = designSearchDtos.get(0);
        String source = erpVoucherDesignSearchDto.getSource();

        //2.查询 单据 对应 表名
        ErpVoucherTable erpVoucherTable = erpVoucherTableService.getErpVoucherTable(source);
        String voucherTypeCode = erpVoucherTable.getVoucherTypeCode();
        HashMap<String,Object> paramMap = new HashMap<>();
        //3. 动态查询
        //3.1 生成动态参数
        getDynamicParamMap(paramMap,designSearchDtos);
        /***************** 设置 仓库 数据查询权限 —— 开始 *****************/
        List<String> ReceiveVouchers = Arrays.asList(ReceiveVoucherArr);
        List<String> DispatchVouchers = Arrays.asList(DispatchVoucherArr);
        List<String> isMyWarehouseVouchers = Arrays.asList(isMyWarehouseVoucherArr);
        if( (ReceiveVouchers.contains(voucherTypeCode) || DispatchVouchers.contains(voucherTypeCode) || (isMyWarehouseVouchers.contains(voucherTypeCode)  &&  dynamicVoucherDto.getIsMyWarehouse())) && 3 != type){
            List<Long> inWarehouseIds = iInWarehouseService.myWarehouseIds();
            if(null == inWarehouseIds || inWarehouseIds.size() == 0){
                dynamicVoucherDto.setIsSelectCreateData(true);
            }else{
                dynamicVoucherDto.setInWarehouseIds(inWarehouseIds);
            }
        }else{
            dynamicVoucherDto.setInWarehouseIds(null);
        }
        /***************** 设置 仓库 数据查询权限 —— 结束 *****************/
        Page<HashMap<String, Object>> hashMapPage = baseMapper.voucherDynamicPage(currentAccountId,dynamicVoucherDto, erpVoucherTable, paramMap, dynamicVoucherDto.getPage());
        // 3.2 查询 明细
        if (!isSearchDetail)return hashMapPage;
        List<HashMap<String, Object>> records = hashMapPage.getRecords();
        List<Object> idList = records.stream().map(item -> item.get("id")).collect(Collectors.toList());
        String ids = StringUtils.join(idList, ",");
        if(StringUtils.isNotBlank(ids)){
            List<ErpVoucherDesign> currentErpVoucherDesign = new ArrayList<>();
            designSearchDtos.forEach(f->{
                ErpVoucherDesign erpVoucherDesign = new ErpVoucherDesign();
                BeanUtils.copyProperties(f,erpVoucherDesign);
                currentErpVoucherDesign.add(erpVoucherDesign);
            });
            List<HashMap<String, Object>> detailList = baseMapper.voucherDynamicDetailListByIds(currentAccountId,currentErpVoucherDesign,dynamicVoucherDto, erpVoucherTable, ids);
            // 3.3 组装明细数据
            HashMap<String,List<HashMap<String, Object>>> detailMap =  new HashMap<>();
            detailList.forEach(detail->{
                Object orderId = detail.get("orderId");
                if(null != orderId){
                    String idStr = orderId.toString();
                    List<HashMap<String, Object>> hashMaps = detailMap.get(idStr);
                    if(null == hashMaps){
                        hashMaps = new ArrayList<>();
                        detailMap.put(idStr,hashMaps);
                    }
                    hashMaps.add(detail);
                }
            });
            // 3.4 把明细数据 加入到主表中
            records.forEach(main->{
                Object id = main.get("id");
                if(null != id){
                    String idStr = id.toString();
                    List<HashMap<String, Object>> hashMaps = detailMap.get(idStr);
                    if(null != hashMaps){
                        main.put("detailList",hashMaps);
                    }
                }
            });
        }
        return hashMapPage;
    }



    @Override
    public HashMap<String, Object> voucherDynamicById(DynamicVoucherDetailDto dynamicVoucherDetailDto) {
        UserInfo userInfo = UserThreadLocal.get();
        DataScope dataScope = userInfo.getDataScope();
        Integer type = dataScope.getType();
        String source = dynamicVoucherDetailDto.getSource();
//        if (StringUtils.isBlank(source))throw new NuoNiuException("单据类型 不能为空");
        if (StringUtils.isBlank(source))return null;
        Integer currentId = dynamicVoucherDetailDto.getCurrentId();
        Integer actionType = dynamicVoucherDetailDto.getActionType();
        String someBusinessType = dynamicVoucherDetailDto.getSomeBusinessType();

        DynamicVoucherDetailBo dynamicVoucherDetailBo = new DynamicVoucherDetailBo();
        Integer currentAccountId = erpAccountService.getCurrentAccountId();
        //查询 单据 对应 表名
        ErpVoucherTable erpVoucherTable = erpVoucherTableService.getErpVoucherTable(source);
        String tableName = erpVoucherTable.getTableName();
        String voucherTypeCode = erpVoucherTable.getVoucherTypeCode();

        /******************** 组装查询条件 LastSql  -- Start -- ***********************/
        String lastSql = dynamicVoucherDetailBo.getLastSql();
        if (StringUtils.isNotBlank(someBusinessType) && !dynamicVoucherDetailDto.equals("Contract")){
            boolean matches = someBusinessType.matches(STR_ENG_PATTERN);
            if (!matches)throw new NuoNiuException("指定业务类型 参数错误");
            lastSql += " AND tab.business_type  in ("+someBusinessType+")";
        }

        //应收应付期初
        if(dynamicVoucherDetailDto.getBeginStartFlag() != null) {
            lastSql += " AND tab.begin_start_flag = " + dynamicVoucherDetailDto.getBeginStartFlag() + " ";
        }

        /***************** 设置 仓库 数据查询权限 —— 开始 *****************/
        List<String> ReceiveVouchers = Arrays.asList(ReceiveVoucherArr);
        List<String> DispatchVouchers = Arrays.asList(DispatchVoucherArr);
        List<String> isMyWarehouseVouchers = Arrays.asList(isMyWarehouseVoucherArr);
        if((  ReceiveVouchers.contains(voucherTypeCode) || DispatchVouchers.contains(voucherTypeCode) || (isMyWarehouseVouchers.contains(voucherTypeCode)  &&  dynamicVoucherDetailDto.isMyWarehouse())) && 3 != type ){

            List<Long> inWarehouseIds = iInWarehouseService.myWarehouseIds();
            String inWarehouseIdsStr = StringUtils.join(inWarehouseIds, ",");
            if(null == inWarehouseIds || inWarehouseIds.size() == 0){
                lastSql += " AND tab.create_user_id = " + userInfo.getUserId();
            }else{
                lastSql += " AND (tab.create_user_id = " + userInfo.getUserId() + "  OR tab.warehouse_id in (" + inWarehouseIdsStr + ")   )";
                lastSql = getLastSqlFromVoucherState(dynamicVoucherDetailDto,lastSql);
            }
        }else{
            lastSql = getLastSqlFromVoucherState(dynamicVoucherDetailDto,lastSql);
        }

        /***************** 设置 仓库 数据查询权限 —— 结束 *****************/

        /******************** 处理  单据数据来源 -- 开始 ***********************/
        if("scw_delivery_entry".equals(tableName)){
            lastSql += " AND tab.data_source = '" + voucherTypeCode +"'";
        }

        String dataSource = dynamicVoucherDetailDto.getDataSource();
        if (StringUtils.isNotBlank(dataSource)){
            if (StringUtils.isBlank(lastSql))lastSql = "";
            lastSql += " AND tab.data_source = '" + dataSource +"'";
        }
        //去除 AND
        if (StringUtils.startsWith(lastSql," AND")){
            lastSql = StringUtils.replaceOnce(lastSql," AND","");
        }
        dynamicVoucherDetailBo.setLastSql(lastSql);
        /******************** 处理  单据数据来源 -- 结束 ***********************/

        /******************** 处理退货业务 LastSql  -- End -- ***********************/
        Integer id = currentId;
        //一、获取真实的ID
        //1.获取最新的ID
        if(null == currentId){
            id = baseMapper.getLastId(tableName, userInfo.getCompanyId(),currentAccountId,dynamicVoucherDetailBo);
        }else{
            if(null != actionType){
                switch (actionType){
                    //上一页
                    case 1: id = baseMapper.getPreId(tableName, userInfo.getCompanyId(),currentAccountId,currentId,dynamicVoucherDetailBo);break;
                    //下一页
                    case 2: id = baseMapper.getNextId(tableName, userInfo.getCompanyId(),currentAccountId,currentId,dynamicVoucherDetailBo);break;
                    //第一页
                    case 3: id = baseMapper.getFirstId(tableName, userInfo.getCompanyId(),currentAccountId,dynamicVoucherDetailBo);break;
                    //最后一页
                    case 4: id = baseMapper.getLastId(tableName, userInfo.getCompanyId(),currentAccountId,dynamicVoucherDetailBo);break;
                }
            }
        }
        if(null == id || (id.equals(currentId) && (null != actionType && (3 == actionType || 4 == actionType))))return null;

        //二、查询详情
        //1.查询 单据设计
        ErpVoucherDesignSearchDto erpVoucherDesignSearchDto = new ErpVoucherDesignSearchDto();
        erpVoucherDesignSearchDto.setSource(source);
        List<ErpVoucherDesign> currentErpVoucherDesign = getCurrentErpVoucherDesign(erpVoucherDesignSearchDto);
        if (null == currentErpVoucherDesign || 0 == currentErpVoucherDesign.size()){
            throw new NuoNiuException("参数错误");
        }

        //3.查询 数据
        //3.1 查询主表数据
        HashMap<String, Object> result = baseMapper.voucherDynamicById(currentAccountId,currentErpVoucherDesign, erpVoucherTable, id);
        if(null != result){
            String ids = "" + id;
            //3.2 查询明细数据
            List<HashMap<String, Object>> detailList = baseMapper.voucherDynamicDetailListByIds(currentAccountId,currentErpVoucherDesign,new DynamicVoucherDto() ,erpVoucherTable, ids);
            result.put("detailList",detailList);

            List<String> moreDetailVoucherList = new ArrayList<>(Arrays.asList(moreDetailVoucherArr));
            /** 设置 更多层级 明细数据 */
            if(moreDetailVoucherList.contains(voucherTypeCode)){
                this.setMoreDetails(detailList,voucherTypeCode,id);
            }
        }

        return result;
    }

    @Override
    public void setMoreDetails(List<HashMap<String, Object>> details, String voucherTypeCode,Integer mainId) {
        if("ProductionWork".equals(voucherTypeCode)|| "DelegateProductionWork".equals(voucherTypeCode)){
            VProductionWorkDetailSimpleVo vProductionWorkDetailSimpleVo = productionWorkDetailService.getVProductionWorkDetailSimpleVo(mainId.longValue());
            HashMap<String,List<VProductionWorkInventoryDetail>> inventoryDetailMap = new HashMap<>();
            HashMap<String,List<VProductionWorkProcedureDetail>> procedureDetailMap = new HashMap<>();
            /** 物料明细 */
            List<VProductionWorkInventoryDetail> inventoryDetails = vProductionWorkDetailSimpleVo.getInventoryDetails();
            inventoryDetails.forEach(inventoryDetail ->{
                Integer productionWorkDetailId = inventoryDetail.getProductionWorkDetailId();
                List<VProductionWorkInventoryDetail> productionWorkInventoryDetailList = inventoryDetailMap.computeIfAbsent(productionWorkDetailId.toString(), k -> new ArrayList<>());
                productionWorkInventoryDetailList.add(inventoryDetail);
            });
            /** 工序明细 */
            List<VProductionWorkProcedureDetailVo> procedureDetails = vProductionWorkDetailSimpleVo.getProcedureDetails();
            procedureDetails.forEach(procedureDetail -> {
                Integer productionWorkDetailId = procedureDetail.getProductionWorkDetailId();
                List<VProductionWorkProcedureDetail> productionWorkProcedureDetailList = procedureDetailMap.computeIfAbsent(productionWorkDetailId.toString(), k -> new ArrayList<>());
                productionWorkProcedureDetailList.add(procedureDetail);
            });
            /** 赋值 */
            details.forEach(detail->{
                String id = detail.get("id").toString();
                List<VProductionWorkInventoryDetail> productionWorkInventoryDetailList = inventoryDetailMap.get(id);
                List<VProductionWorkProcedureDetail> productionWorkProcedureDetailList = procedureDetailMap.get(id);
                if(null != productionWorkInventoryDetailList){
                    detail.put("productionWorkInventoryDetailList",productionWorkInventoryDetailList);
                }
                if(null != productionWorkProcedureDetailList){
                    detail.put("productionWorkProcedureDetailList",productionWorkProcedureDetailList);
                }
            });
        }

    }


    /**
     * 查询 指定单据明细 记录
     * @param detailIds             单据明细ID
     * @param voucherDesignIds      单据设计ID
     * @param voucherTypeCode       单据唯一编码
     * @return
     */
    @Override
    public List<HashMap<String, Object>> getSpecifyFieldRecord(List<Integer> detailIds, List<Integer> voucherDesignIds, String voucherTypeCode) {
        QueryWrapper<ErpVoucherDesign> queryWrapper = new QueryWrapper<>();
        queryWrapper.in("id",voucherDesignIds);
        List<ErpVoucherDesign> erpVoucherDesignList = list(queryWrapper);
        ErpVoucherTable erpVoucherTable = erpVoucherTableService.getErpVoucherTable(voucherTypeCode);
        List<HashMap<String, Object>> specifyFieldRecord = baseMapper.getSpecifyFieldRecord(erpVoucherDesignList, erpVoucherTable, detailIds);
        return specifyFieldRecord;
    }

    @Override
    public List<ErpBarcodeMainInfo> listByVoucherTable(List<Integer> detailIds, String voucherTypeCode) {
        ErpVoucherTable erpVoucherTable = erpVoucherTableService.getErpVoucherTable(voucherTypeCode);
        List<ErpBarcodeMainInfo> erpBarcodeMainInfos = baseMapper.listByVoucherTable(erpVoucherTable, detailIds);
        erpBarcodeMainInfos.forEach(f->f.setSourceVoucherType(erpVoucherTable.getVoucherTypeCode()));
        return erpBarcodeMainInfos;
    }


    private String getLastSqlFromVoucherState(DynamicVoucherDetailDto dynamicVoucherDetailDto,String lastSql){
        Integer startVoucherState = dynamicVoucherDetailDto.getStartVoucherState();
        Integer endVoucherState = dynamicVoucherDetailDto.getEndVoucherState();
        List<Integer> voucherStateList = dynamicVoucherDetailDto.getVoucherStateList();
        if (null != startVoucherState || null != endVoucherState || (null != voucherStateList && voucherStateList.size() > 0)){
            String voucherStateSql = "";
            if(null != startVoucherState && null == endVoucherState){
                voucherStateSql += " OR tab.voucher_state > " + startVoucherState;
            }
            if(null != endVoucherState && null == startVoucherState){
                voucherStateSql += " OR tab.voucher_state < " + endVoucherState;
            }
            if(null != startVoucherState && null != endVoucherState ){
                voucherStateSql += " OR ( tab.voucher_state > "+startVoucherState+" AND tab.voucher_state < " + endVoucherState + ")";
            }
            if (null != voucherStateList && voucherStateList.size() > 0){
                String voucherStateListJoinStr = StringUtils.join(voucherStateList, ",");
                voucherStateSql += " OR tab.voucher_state in (" +voucherStateListJoinStr+ ")";
            }
            if (StringUtils.startsWith(voucherStateSql," OR")){
                voucherStateSql = StringUtils.replaceOnce(voucherStateSql," OR","");
            }
            lastSql += " AND (" + voucherStateSql +") ";
        }

        return lastSql;

    }
    /**
     * 计算 累计执行数量 情况（当前单据明细 数量 不超出 来源单据 剩余执行数量）
     * @param voucherMainBo 当前单据主表
     * @param voucherDetailBoList 当前单据明细
     * @param voucherSearchBo 查询条件
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void calculateSourceVoucher(VoucherMainBo voucherMainBo, List<VoucherDetailBo> voucherDetailBoList,VoucherSearchBo voucherSearchBo) {
        Integer currentBusinessType = voucherMainBo.getBusinessType();
        boolean isGetRet = false;
        //判断 是不是 退货业务(查询 累计退货字段)
        //[{"key":30,"label":"委外到货"},{"key":31,"label":"委外退货(冲抵)"},{"key":32,"label":"委外退货"}]
        // 96:销售退货(冲抵) 97: 采购退货(冲抵) 98.销售退货 99.采购退货 100:期初
        List<Integer> retBusinessType = Arrays.asList(retBusinessTypeArr);
        if(retBusinessType.contains(currentBusinessType)){
            isGetRet = true;
        }
        Integer currentAccountId = erpAccountService.getCurrentAccountId();
        UserInfo userInfo = UserThreadLocal.get();
        Integer companyId = userInfo.getCompanyId();
        String voucherType = voucherSearchBo.getVoucherType();
        String sourceVoucherType = voucherSearchBo.getSourceVoucherType();
        Integer sourceVoucherId = voucherSearchBo.getSourceVoucherId();
        //查询 来源单据 对应 表名
        ErpVoucherTable erpVoucherTable = erpVoucherTableService.getErpVoucherTable(sourceVoucherType);
        String tableName = erpVoucherTable.getTableName();
        String detailTableName = erpVoucherTable.getDetailTableName();
        //查询 来源单据 主表
        VoucherMainBo sourceMain = baseMapper.getVoucherMainBoById(tableName, companyId, currentAccountId, sourceVoucherId,isGetRet);
        if(null == sourceMain)throw new NuoNiuException("单据明细校验错误：查询不到来源单据");
        Integer businessType = sourceMain.getBusinessType();
        List<Integer> noNextVoucherBusinessType = Arrays.asList(noNextVoucherBusinessTypeArr);
        if(noNextVoucherBusinessType.contains(businessType))throw new NuoNiuException("单据明细校验错误：冲抵单据不能生单");
        BigDecimal mainCumExecuteQuantity = sourceMain.getCumExecuteQuantity();

        //获取 来源单据主表 累计退货数量
        BigDecimal mainCumRetQuantity = sourceMain.getCumRetQuantity();
        //查询 来源单据 明细
        List<VoucherDetailBo> sourceDetailList = baseMapper.getVoucherDetailBoByMainId(detailTableName, companyId, sourceMain.getId().intValue(),isGetRet);
        //1.判断 来源单据状态
        Integer sourceState = sourceMain.getVoucherState();
        List<String> applyVouchers = Arrays.asList(applyVoucherArr);
//        if (applyVouchers.contains(sourceVoucherType) && sourceState < 2 && 1 == voucherSearchBo.getCalculateType()){
//            throw new NuoNiuException("单据明细校验错误：来源单据未提交,不能生单");
//        }else
            if( 0 == sourceState && 1 == voucherSearchBo.getCalculateType()){
            throw new NuoNiuException("单据明细校验错误：来源单据未审核,不能生单");
        }

        if( 10 == sourceState && 1 == voucherSearchBo.getCalculateType() && voucherMainBo.getIsNewMain())throw new NuoNiuException("单据明细校验错误：来源单据已经关闭,不能生单");
        //2.校验 明细数量 是否超标
        Map<String,VoucherDetailBo> sourceDetailMap = new HashMap<>();
        sourceDetailList.forEach(detail-> sourceDetailMap.put(detail.getInventoryId() +"_"+ detail.getId(), detail));
        List<VoucherDetailBo> editVoucherDetailBoList = new ArrayList<>();
        //循环 当前单据明细
        for (VoucherDetailBo detailBo: voucherDetailBoList){
            VoucherDetailBo sourceDetail = sourceDetailMap.get(detailBo.getInventoryId() +"_"+ detailBo.getSourceDetailId());
            if( null == sourceDetail )throw new NuoNiuException("单据明细校验错误:在来源单据明细中，查询不到："+ detailBo.getInventoryName() + " 的物料");
            //3.1
            String cumExecuteJson = sourceDetail.getCumExecuteJson();
            List<CumExecuteDetailBo> cumExecuteDetailBos = JSONObject.parseArray(cumExecuteJson, CumExecuteDetailBo.class);
            if(null == cumExecuteDetailBos)cumExecuteDetailBos = new ArrayList<>();
            CumExecuteDetailBo newCumExecuteDetailBo = null;
            boolean isNewCumExecuteDetailBo = true;
            for (CumExecuteDetailBo item: cumExecuteDetailBos){
                if(item.getDetailId().equals(detailBo.getId()) && item.getVoucherType().equals(voucherType)){
                    newCumExecuteDetailBo = item;
                    isNewCumExecuteDetailBo = false;
                    break;
                }
            }
            //获取 来源明细 累计执行数量
            BigDecimal cumExecuteQuantity = sourceDetail.getCumExecuteQuantity();
            //获取 来源明细 主单位数量
            BigDecimal baseQuantity = sourceDetail.getBaseQuantity().abs();
            //获取 当前单据明细 的主单位数量
            BigDecimal currentBaseQuantity = detailBo.getBaseQuantity().abs();
            BigDecimal subtract;
            BigDecimal fCumExecuteQuantity;
            /**************************************/
            //获取 来源明细 累计退货数量
            BigDecimal cumRetQuantity = sourceDetail.getCumRetQuantity();
            BigDecimal subtractRet = BigDecimal.ZERO;
            //新的 明细 累计退货数量
            BigDecimal fCumRetQuantity ;
            /**************************************/
            //保存 处理
            if(1 == voucherSearchBo.getCalculateType()){
                //3.1.1 如果是 新加入的执行情况
                if(isNewCumExecuteDetailBo){
                    newCumExecuteDetailBo = new CumExecuteDetailBo();
                    cumExecuteDetailBos.add(newCumExecuteDetailBo);
                    //计算 剩余执行数量
                    subtract = baseQuantity.subtract(cumExecuteQuantity);
                    //计算 累计执行数量
                    fCumExecuteQuantity = cumExecuteQuantity.add(currentBaseQuantity);
                    //累加 来源单据主表 累计执行数量
                    mainCumExecuteQuantity = mainCumExecuteQuantity.add(currentBaseQuantity);
                    //2.判断 是否冲抵，如果是，就需要更新退货数量(只有到货、发货、出入库和发票 的单据才会有)
                    if( noNextVoucherBusinessType.contains(currentBusinessType) ){
                        subtractRet = baseQuantity.subtract(cumRetQuantity);
                        fCumRetQuantity = cumRetQuantity.add(currentBaseQuantity);
                        sourceDetail.setCumRetQuantity(fCumRetQuantity);
                        //累加 来源单据主表 累计执行数量
                        mainCumRetQuantity = mainCumRetQuantity.add(currentBaseQuantity);
                    }else{
                        sourceDetail.setCumRetQuantity(null);
                    }
                }else{
                    // 获取 更新前的
                    BigDecimal oldBaseQuantity= newCumExecuteDetailBo.getExecuteQuantity();
                    //如果当前单据明细 和 原来执行数量 一样,则执行下一个循环
                    if(oldBaseQuantity.compareTo(currentBaseQuantity) == 0)continue;
                    subtract = baseQuantity.add(oldBaseQuantity).subtract(cumExecuteQuantity);
                    fCumExecuteQuantity = cumExecuteQuantity.subtract(oldBaseQuantity).add(currentBaseQuantity);
                    //累加 来源单据主表 累计执行数量
                    mainCumExecuteQuantity = mainCumExecuteQuantity.subtract(oldBaseQuantity).add(currentBaseQuantity);
                    //2.判断 是否冲抵，如果是，就需要更新退货数量(只有到货、发货、出入库和发票 的单据才会有)
                    if( noNextVoucherBusinessType.contains(currentBusinessType) ){
                        subtractRet = baseQuantity.add(oldBaseQuantity).subtract(cumRetQuantity);
                        fCumRetQuantity = cumRetQuantity.subtract(oldBaseQuantity).add(currentBaseQuantity);
                        sourceDetail.setCumRetQuantity(fCumRetQuantity);
                        //累加 来源单据主表 累计执行数量
                        mainCumRetQuantity = mainCumRetQuantity.subtract(oldBaseQuantity).add(currentBaseQuantity);
                    }else{
                        //不更新
                        sourceDetail.setCumRetQuantity(null);
                    }
                }
                //a.比较 当前单据 明细数量
                if(subtract.compareTo(currentBaseQuantity) < 0)throw new NuoNiuException("物料名称：" + detailBo.getInventoryName() + " 的数量已大于未执行数量（"+ subtract +"）");
                // 退货业务 剩余判断
                if( noNextVoucherBusinessType.contains(currentBusinessType) ){
                    if(subtractRet.compareTo(currentBaseQuantity) < 0)throw new NuoNiuException("物料名称：" + detailBo.getInventoryName() + "的退货数量已大于未退货数量（"+ subtractRet +"）");
                }
                //b.更新 来源单据明细 累计执行数量
                sourceDetail.setCumExecuteQuantity(fCumExecuteQuantity);
                //c.更新 来源单据明细 执行情况
                newCumExecuteDetailBo.setVoucherType(voucherType);
                newCumExecuteDetailBo.setDetailId(detailBo.getId());
                newCumExecuteDetailBo.setExecuteQuantity(currentBaseQuantity);
                String newCumExecuteJson = JSONObject.toJSONString(cumExecuteDetailBos);
                sourceDetail.setCumExecuteJson(newCumExecuteJson);
                //d.添加 需要更新的 来源单据明细
                editVoucherDetailBoList.add(sourceDetail);
            }else{
                if(isNewCumExecuteDetailBo){
//                    throw new NuoNiuException("删除当前单据出错：当前单据明细与来源单据明细 不存在执行关系");
                }else {
                    //移除 来源单据明细的 执行情况
                    cumExecuteDetailBos.remove(newCumExecuteDetailBo);
                    //减去 来源单据主表 累计执行数量
                    mainCumExecuteQuantity = mainCumExecuteQuantity.subtract(newCumExecuteDetailBo.getExecuteQuantity());
                    //b.更新 来源单据明细 累计执行数量
                    fCumExecuteQuantity = cumExecuteQuantity.subtract(newCumExecuteDetailBo.getExecuteQuantity());
                    sourceDetail.setCumExecuteQuantity(fCumExecuteQuantity);
                    String newCumExecuteJson = JSONObject.toJSONString(cumExecuteDetailBos);
                    sourceDetail.setCumExecuteJson(newCumExecuteJson);

                    //2.判断 是否冲抵，如果是，就需要更新退货数量(只有到货、发货、出入库和发票 的单据才会有)
                    if( noNextVoucherBusinessType.contains(currentBusinessType) ){
                        fCumRetQuantity = cumRetQuantity.subtract(newCumExecuteDetailBo.getExecuteQuantity());
                        sourceDetail.setCumRetQuantity(fCumRetQuantity);
                        //累加 来源单据主表 累计执行数量
                        mainCumRetQuantity = mainCumRetQuantity.subtract(newCumExecuteDetailBo.getExecuteQuantity());
                    }else{
                        //不更新
                        sourceDetail.setCumRetQuantity(null);
                    }
                    //d.添加 需要更新的 来源单据明细
                    editVoucherDetailBoList.add(sourceDetail);
                }
            }
        }
        //更新判断：如果 来源单据 有数据变动 就更新
        if(editVoucherDetailBoList.size() > 0 ){
            CalculateSourceVoucherUpdateBo calculateSourceVoucherUpdateBo = new CalculateSourceVoucherUpdateBo();
            calculateSourceVoucherUpdateBo.setId(sourceMain.getId());
            calculateSourceVoucherUpdateBo.setTableName(tableName);
            calculateSourceVoucherUpdateBo.setCompanyId(companyId);
            calculateSourceVoucherUpdateBo.setCurrentAccountId(currentAccountId);
            calculateSourceVoucherUpdateBo.setCumExecuteQuantity(mainCumExecuteQuantity);
            //如果是冲抵业务，则需要更新累计退货数量
            if( noNextVoucherBusinessType.contains(currentBusinessType) ){
                calculateSourceVoucherUpdateBo.setCumRetQuantity(mainCumRetQuantity);
            }
            if(sourceState != 2){
                if(mainCumExecuteQuantity.compareTo(sourceMain.getTotalQuantity()) < 0){
                    calculateSourceVoucherUpdateBo.setVoucherState(1);
                    calculateSourceVoucherUpdateBo.setReleaseState(1);
                }else{
                    calculateSourceVoucherUpdateBo.setVoucherState(10);
                    calculateSourceVoucherUpdateBo.setReleaseState(2);
                    if(calculateSourceVoucherUpdateBo.getTableName().equals("scs_order") || calculateSourceVoucherUpdateBo.equals("scp_requisition") || calculateSourceVoucherUpdateBo.getTableName().equals("scp_order")) {
                        calculateSourceVoucherUpdateBo.setClosedState(0);
                    }
                }
            }
            //4.更新 来源单据 主表 累计执行数量
            baseMapper.updateSourceVoucherMainCumExecuteQuantity(calculateSourceVoucherUpdateBo);
            //5.批量更新 来源单据明细 累计执行情况
            baseMapper.updateBatchSourceVoucherDetail(detailTableName,companyId,currentAccountId,editVoucherDetailBoList);
        }
    }

    /**
     * 计算 累计退货数量 情况
     * @param voucherMainRetBo
     * @param voucherDetailRetBoList
     * @param voucherSearchBo
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void calculateRetQuantity(VoucherMainRetBo voucherMainRetBo, List<VoucherDetailRetBo> voucherDetailRetBoList, VoucherSearchBo voucherSearchBo) {
        List<Integer> noNextVoucherBusinessType = Arrays.asList(noNextVoucherBusinessTypeArr);
        Integer currentAccountId = erpAccountService.getCurrentAccountId();
        UserInfo userInfo = UserThreadLocal.get();
        Integer companyId = userInfo.getCompanyId();
        String voucherType = voucherSearchBo.getVoucherType();
        String sourceVoucherType = voucherSearchBo.getSourceVoucherType();
        Integer sourceVoucherId = voucherSearchBo.getSourceVoucherId();
        //查询 来源单据 对应 表名
        ErpVoucherTable erpVoucherTable = erpVoucherTableService.getErpVoucherTable(sourceVoucherType);
        String tableName = erpVoucherTable.getTableName();
        String detailTableName = erpVoucherTable.getDetailTableName();
        //查询 来源单据 主表
        VoucherMainRetBo sourceMain = baseMapper.getVoucherMainRetBoById(tableName, companyId, currentAccountId, sourceVoucherId);
        if(null == sourceMain)throw new NuoNiuException("校验累计退货情况：查询不到来源单据");
        Integer businessType = sourceMain.getBusinessType();
        if( noNextVoucherBusinessType.contains(businessType) )throw new NuoNiuException("单据明细校验错误：冲抵单据不能生单");
//        //业务判断
//        if(("PuArrival".equals(sourceMain) && 99 == sourceMain.getBusinessType()))throw new NuoNiuException("采购退货单的来源单，不能是采购退货单");
//        if(("SaleDelivery".equals(sourceMain) && 98 == sourceMain.getBusinessType()))throw new NuoNiuException("销售退货单的来源单，不能是销售退货单");
        BigDecimal mainCumRetQuantity = sourceMain.getCumRetQuantity();
        //查询 来源单据 明细
        List<VoucherDetailRetBo> sourceDetailList = baseMapper.getVoucherDetailRetBoByMainId(detailTableName, companyId, sourceMain.getId().intValue());

        //1.判断 来源单据状态
        Integer sourceState = sourceMain.getVoucherState();
        if( 0 == sourceState && 1 == voucherSearchBo.getCalculateType())throw new NuoNiuException("单据明细校验错误：来源单据未审核,不能生单");
//        if(10 == sourceState && 1 == voucherSearchBo.getCalculateType())throw new NuoNiuException("校验累计退货情况：来源单据已经关闭");
        //2.校验 明细数量 是否超标
        Map<String,VoucherDetailRetBo> sourceDetailMap = new HashMap<>();
        sourceDetailList.forEach(detail-> sourceDetailMap.put(detail.getInventoryId() +"_"+ detail.getId(), detail));
        //
        if(sourceDetailMap.size() != sourceDetailList.size())throw new NuoNiuException("来源明细不能重复");
        List<VoucherDetailRetBo> editVoucherDetailRetBoList = new ArrayList<>();
        for (VoucherDetailRetBo detailBo: voucherDetailRetBoList){
            VoucherDetailRetBo sourceDetail = sourceDetailMap.get(detailBo.getInventoryId() +"_"+ detailBo.getSourceDetailId());
            if( null == sourceDetail )throw new NuoNiuException("校验累计退货情况:明细匹配错误");
            //3.1
            String cumRetJson = sourceDetail.getCumRetJson();
            List<CumExecuteDetailBo> cumRetDetailBos = JSONObject.parseArray(cumRetJson, CumExecuteDetailBo.class);
            if(null == cumRetDetailBos)cumRetDetailBos = new ArrayList<>();
            CumExecuteDetailBo newCumExecuteDetailBo = null;
            boolean isNewCumExecuteDetailBo = true;
            for (CumExecuteDetailBo item: cumRetDetailBos){
                if(item.getDetailId().equals(detailBo.getId()) && item.getVoucherType().equals(voucherType)){
                    newCumExecuteDetailBo = item;
                    isNewCumExecuteDetailBo = false;
                    break;
                }
            }
            //获取 来源明细 累计退货数量
            BigDecimal cumRetQuantity = sourceDetail.getCumRetQuantity();
            //获取 来源明细 主单位数量
            BigDecimal baseQuantity = sourceDetail.getBaseQuantity().abs();
            //获取 当前单据明细 的主单位数量
            BigDecimal currentBaseQuantity = detailBo.getBaseQuantity().abs();
            //剩余可退货数量
            BigDecimal subtract ;
            BigDecimal fCumRetQuantity ;
            //处理 保存情况
            if(1 == voucherSearchBo.getCalculateType()){
                //3.1.1 如果是 新加入的执行情况
                if(isNewCumExecuteDetailBo){
                    newCumExecuteDetailBo = new CumExecuteDetailBo();
                    cumRetDetailBos.add(newCumExecuteDetailBo);
                    subtract = baseQuantity.subtract(cumRetQuantity);
                    fCumRetQuantity = cumRetQuantity.add(currentBaseQuantity);
                    //累加 来源单据主表 累计执行数量
                    mainCumRetQuantity = mainCumRetQuantity.add(currentBaseQuantity);
                }else{
                    // 获取 更新前的
                    BigDecimal oldBaseQuantity= newCumExecuteDetailBo.getExecuteQuantity();
                    //如果当前单据明细 和 原来执行数量 一样,则执行下一个循环
                    if(oldBaseQuantity.compareTo(currentBaseQuantity) == 0)continue;
                    subtract = baseQuantity.add(oldBaseQuantity).subtract(cumRetQuantity);
                    fCumRetQuantity = cumRetQuantity.subtract(oldBaseQuantity).add(currentBaseQuantity);
                    //累加 来源单据主表 累计执行数量
                    mainCumRetQuantity = mainCumRetQuantity.subtract(oldBaseQuantity).add(currentBaseQuantity);
                }
                //a.比较 当前单据 明细数量
                if(subtract.compareTo(currentBaseQuantity) < 0)throw new NuoNiuException("物料名称：" + detailBo.getInventoryName() + "的退货数量已超出范围（剩余"+ subtract +"）");
                //b.更新 来源单据明细 累计退货数量
                sourceDetail.setCumRetQuantity(fCumRetQuantity);
                //c.更新 来源单据明细 退货情况
                newCumExecuteDetailBo.setVoucherType(voucherType);
                newCumExecuteDetailBo.setDetailId(detailBo.getId());
                newCumExecuteDetailBo.setExecuteQuantity(currentBaseQuantity);
                String newCumRetJson = JSONObject.toJSONString(cumRetDetailBos);
                sourceDetail.setCumRetJson(newCumRetJson);
                //d.添加 需要更新的 来源单据明细
                editVoucherDetailRetBoList.add(sourceDetail);
            }
            //处理 删除情况
            else{
                if(isNewCumExecuteDetailBo){
                    throw new NuoNiuException("删除当前单据出错：当前单据明细与来源单据明细 不存在执行关系");
                }else {
                    //移除 来源单据明细的 执行情况
                    cumRetDetailBos.remove(newCumExecuteDetailBo);
                    //减去 来源单据主表 累计退货数量
                    mainCumRetQuantity = mainCumRetQuantity.subtract(newCumExecuteDetailBo.getExecuteQuantity());
                    //b.更新 来源单据明细 累计退货数量
                    fCumRetQuantity = cumRetQuantity.subtract(newCumExecuteDetailBo.getExecuteQuantity());
                    sourceDetail.setCumRetQuantity(fCumRetQuantity);
                    String newCumRetJson = JSONObject.toJSONString(cumRetDetailBos);
                    sourceDetail.setCumRetJson(newCumRetJson);
                    //d.添加 需要更新的 来源单据明细
                    editVoucherDetailRetBoList.add(sourceDetail);
                }
            }

        }
        //如果 来源单据 有数据变动 就更新
        if(editVoucherDetailRetBoList.size() > 0 ){
            //4.更新 来源单据 主表 累计退货数量
            baseMapper.updateSourceVoucherMainCumRetQuantity(tableName,companyId,currentAccountId,sourceMain.getId().intValue(),mainCumRetQuantity);
            //5.批量更新 来源单据明细 累计退货情况
            baseMapper.updateBatchSourceVoucherDetailRet(detailTableName,companyId,currentAccountId,editVoucherDetailRetBoList);
        }


    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void calculateInvoiceVoucher(VoucherInvoiceMainBo voucherInvoiceMainBo, List<VoucherInvoiceDetailBo> voucherInvoiceDetailBoList, VoucherSearchBo voucherSearchBo) {
        Integer currentBusinessType = voucherInvoiceMainBo.getBusinessType();
        Integer currentAccountId = erpAccountService.getCurrentAccountId();
        UserInfo userInfo = UserThreadLocal.get();
        Integer companyId = userInfo.getCompanyId();
        String voucherType = voucherSearchBo.getVoucherType();
        String sourceVoucherType = voucherSearchBo.getSourceVoucherType();
        Integer sourceVoucherId = voucherSearchBo.getSourceVoucherId();
        //查询 来源单据 对应 表名
        ErpVoucherTable erpVoucherTable = erpVoucherTableService.getErpVoucherTable(sourceVoucherType);
        String tableName = erpVoucherTable.getTableName();
        String detailTableName = erpVoucherTable.getDetailTableName();
        //查询 来源单据 主表
        VoucherInvoiceMainBo sourceMain = baseMapper.getVoucherInvoiceMainBoById(tableName, companyId, currentAccountId, sourceVoucherId);
        if(null == sourceMain)throw new NuoNiuException("单据明细校验错误：查询不到来源单据");

        BigDecimal mainInvoiceQuantity = sourceMain.getCumInvoiceQuantity();
        if (null == mainInvoiceQuantity)mainInvoiceQuantity = new BigDecimal(0);
        //查询 来源单据 明细
        List<VoucherInvoiceDetailBo> sourceDetailList = baseMapper.getVoucherInvoiceDetailBoByMainId(detailTableName, companyId, sourceMain.getId().intValue());

        //1.判断 来源单据状态
        Integer sourceState = sourceMain.getVoucherState();

        List<String> applyVouchers = Arrays.asList(applyVoucherArr);
//        if (applyVouchers.contains(sourceVoucherType) && sourceState < 2 && 1 == voucherSearchBo.getCalculateType()){
//            throw new NuoNiuException("单据明细校验错误：来源单据未提交,不能生单");
//        }else
            if( 0 == sourceState && 1 == voucherSearchBo.getCalculateType()){
            throw new NuoNiuException("单据明细校验错误：来源单据未审核,不能生单");
        }

        if( null != sourceMain.getCumInvoiceQuantity() && sourceMain.getCumInvoiceQuantity().compareTo(sourceMain.getTotalQuantity()) == 0  && 1 == voucherSearchBo.getCalculateType() && voucherInvoiceMainBo.getIsNewMain())throw new NuoNiuException("单据校验错误：来源单据已经全部生产发票");
        //2.校验 明细数量 是否超标
        Map<String,VoucherInvoiceDetailBo> sourceDetailMap = new HashMap<>();
        sourceDetailList.forEach(detail-> sourceDetailMap.put(detail.getInventoryId() +"_"+ detail.getId(), detail));
        List<VoucherInvoiceDetailBo> editVoucherInvoiceDetailBoList = new ArrayList<>();
        //循环 当前单据明细
        for (VoucherInvoiceDetailBo detailBo: voucherInvoiceDetailBoList){
            VoucherInvoiceDetailBo sourceDetail = sourceDetailMap.get(detailBo.getInventoryId() +"_"+ detailBo.getSourceDetailId());
            if( null == sourceDetail )throw new NuoNiuException("单据明细校验错误:在来源单据明细中，查询不到："+ detailBo.getInventoryName() + " 的物料");
            //3.1
            String cumInvoiceJson = sourceDetail.getCumInvoiceJson();
            List<CumExecuteDetailBo> cumExecuteDetailBos = JSONObject.parseArray(cumInvoiceJson, CumExecuteDetailBo.class);
            if(null == cumExecuteDetailBos)cumExecuteDetailBos = new ArrayList<>();
            CumExecuteDetailBo newCumExecuteDetailBo = null;
            boolean isNewCumExecuteDetailBo = true;
            for (CumExecuteDetailBo item: cumExecuteDetailBos){
                if(item.getDetailId().equals(detailBo.getId()) && item.getVoucherType().equals(voucherType)){
                    newCumExecuteDetailBo = item;
                    isNewCumExecuteDetailBo = false;
                    break;
                }
            }
            //获取 来源明细 累计开票数量
            BigDecimal cumInvoiceQuantity = sourceDetail.getCumInvoiceQuantity();
            //获取 来源明细 主单位数量
            BigDecimal baseQuantity = sourceDetail.getBaseQuantity().abs();
            //获取 当前单据明细 的主单位数量
            BigDecimal currentBaseQuantity = detailBo.getBaseQuantity().abs();
            BigDecimal subtract;
            BigDecimal fCumInvoiceQuantity;
            //保存 处理
            if(1 == voucherSearchBo.getCalculateType()){
                //3.1.1 如果是 新加入的执行情况
                if(isNewCumExecuteDetailBo){
                    //累加 来源单据主表 累计执行数量
                    mainInvoiceQuantity = mainInvoiceQuantity.add(currentBaseQuantity);

                    newCumExecuteDetailBo = new CumExecuteDetailBo();
                    cumExecuteDetailBos.add(newCumExecuteDetailBo);
                    //计算 剩余执行数量
                    subtract = baseQuantity.subtract(cumInvoiceQuantity);
                    //计算 累计执行数量
                    fCumInvoiceQuantity = cumInvoiceQuantity.add(currentBaseQuantity);


                }else{
                    // 获取 更新前的
                    BigDecimal oldBaseQuantity= newCumExecuteDetailBo.getExecuteQuantity();
                    //如果当前单据明细 和 原来执行数量 一样,则执行下一个循环
                    if(oldBaseQuantity.compareTo(currentBaseQuantity) == 0)continue;
                    subtract = baseQuantity.add(oldBaseQuantity).subtract(cumInvoiceQuantity);
                    fCumInvoiceQuantity = cumInvoiceQuantity.subtract(oldBaseQuantity).add(currentBaseQuantity);
                    //累加 来源单据主表 累计执行数量
                    mainInvoiceQuantity = mainInvoiceQuantity.subtract(oldBaseQuantity).add(currentBaseQuantity);
                }
                //a.比较 当前单据 明细数量
                if(subtract.compareTo(currentBaseQuantity) < 0)throw new NuoNiuException("物料名称：" + detailBo.getInventoryName() + "的开票数量已大于未开票数量（"+ subtract +"）");
                //b.更新 来源单据明细 累计开票数量
                sourceDetail.setCumInvoiceQuantity(fCumInvoiceQuantity);
                //c.更新 来源单据明细 开票情况
                newCumExecuteDetailBo.setVoucherType(voucherType);
                newCumExecuteDetailBo.setDetailId(detailBo.getId());
                newCumExecuteDetailBo.setExecuteQuantity(currentBaseQuantity);
                String newCumExecuteJson = JSONObject.toJSONString(cumExecuteDetailBos);
                sourceDetail.setCumInvoiceJson(newCumExecuteJson);
                //d.添加 需要更新的 来源单据明细
                editVoucherInvoiceDetailBoList.add(sourceDetail);
            }else{
                if(isNewCumExecuteDetailBo){
                    throw new NuoNiuException("删除当前单据出错：当前单据明细与来源单据明细 不存在执行关系");
                }else {
                    //移除 来源单据明细的 执行情况
                    cumExecuteDetailBos.remove(newCumExecuteDetailBo);
                    //减去 来源单据主表 累计执行数量
                    mainInvoiceQuantity = mainInvoiceQuantity.subtract(newCumExecuteDetailBo.getExecuteQuantity());
                    //b.更新 来源单据明细 累计执行数量
                    fCumInvoiceQuantity = cumInvoiceQuantity.subtract(newCumExecuteDetailBo.getExecuteQuantity());
                    sourceDetail.setCumInvoiceQuantity(fCumInvoiceQuantity);
                    String newCumExecuteJson = JSONObject.toJSONString(cumExecuteDetailBos);
                    sourceDetail.setCumInvoiceJson(newCumExecuteJson);

                    //d.添加 需要更新的 来源单据明细
                    editVoucherInvoiceDetailBoList.add(sourceDetail);
                }
            }
        }
        //更新判断：如果 来源单据 有数据变动 就更新
        if(editVoucherInvoiceDetailBoList.size() > 0 ){
            CalculateSourceVoucherUpdateBo calculateSourceVoucherUpdateBo = new CalculateSourceVoucherUpdateBo();
            calculateSourceVoucherUpdateBo.setId(sourceMain.getId());
            calculateSourceVoucherUpdateBo.setTableName(tableName);
            calculateSourceVoucherUpdateBo.setCompanyId(companyId);
            calculateSourceVoucherUpdateBo.setCurrentAccountId(currentAccountId);
            calculateSourceVoucherUpdateBo.setCumInvoiceQuantity(mainInvoiceQuantity);

            //4.更新 来源单据 主表 累计发票数量
            baseMapper.updateSourceVoucherMainInvoiceCumQuantity(calculateSourceVoucherUpdateBo);
            //5.批量更新 来源单据明细 累计开票情况
            baseMapper.updateBatchSourceInvoiceVoucherDetail(detailTableName,companyId,currentAccountId,editVoucherInvoiceDetailBoList);
        }
    }


    /**
     * 生成动态参数
     * @param paramMap
     * @param dtos
     */
    private void getDynamicParamMap(HashMap<String,Object> paramMap,List<ErpVoucherDesignSearchDto> dtos){
        dtos.stream().filter(f-> org.apache.commons.lang3.StringUtils.isNotBlank(f.getValue()) || (null != f.getRangDateVal() && f.getRangDateVal().length == 2) ).forEach(item->{
            String code =  item.getCode();
            if(StringUtils.isNotBlank(item.getValue())){
                if(code.equals("voucherDate")) {
                    paramMap.put(code,  item.getValue().substring(0, 10));
                } else {
                    paramMap.put(code, item.getValue());
                }
            }else{
                Object[] rangDateVal = item.getRangDateVal();
                ArrayList rangDate = (ArrayList)rangDateVal[1];
                String startDate = String.valueOf(rangDate.get(0));
                String endDate =String.valueOf(rangDate.get(1));
                paramMap.put(code+ "_startDate",startDate);
                paramMap.put(code+ "_endDate",endDate);
            }
        });
    }

    @Override
    public void initDefErpVoucherDesign( UserInfo userInfo,Integer accountId) {
        LocalDateTime now = LocalDateTime.now();
        baseMapper.initDefErpVoucherDesign(accountId,userInfo.getCompanyId(),userInfo.getCompanyName(),userInfo.getUserId(),userInfo.getRealName(),now );
    }


    /**
     * 单据设计 -- 新增 自定义字段
     * @param erpVoucherDesignAddDto
     */
    @Override
    public void addCustomField(ErpVoucherDesignAddDto erpVoucherDesignAddDto) {
        Integer currentAccountId = erpAccountService.getCurrentAccountId();
        if(null == currentAccountId)throw new NuoNiuException("当前账套已经结算或者没有账套");
        String source = erpVoucherDesignAddDto.getSource();
        String dataTab = erpVoucherDesignAddDto.getDataTab();
        String name = erpVoucherDesignAddDto.getName();
        if(StringUtils.isBlank(source) || StringUtils.isBlank(dataTab) || StringUtils.isBlank(name))throw new NuoNiuException("保存失败，参数错误");
        LocalDateTime now = LocalDateTime.now();
        ZoneId zone = ZoneId.systemDefault();
        Instant instant = now.atZone(zone).toInstant();
        long milli = instant.toEpochMilli();
        String substring = (milli + "").substring(8);
        UserInfo userInfo = UserThreadLocal.get();
        ErpVoucherDesign erpVoucherDesign = new ErpVoucherDesign();
        BeanUtils.copyProperties(erpVoucherDesignAddDto,erpVoucherDesign);
        String code = PinyinUtils.getFirstSpell(erpVoucherDesign.getName());
        erpVoucherDesign.setAccountId(currentAccountId);
        erpVoucherDesign.setCode( "d_"+code + substring );
        erpVoucherDesign.setDataType(2);
        erpVoucherDesign.setSysName(erpVoucherDesign.getName());
        erpVoucherDesign.setCompanyId(userInfo.getCompanyId());
        erpVoucherDesign.setCompanyName((userInfo.getCompanyName()));
        erpVoucherDesign.setCreateDate(now);
        erpVoucherDesign.setCreateUserId(userInfo.getUserId());
        erpVoucherDesign.setCreateUserName(userInfo.getRealName());
        save(erpVoucherDesign);
    }

    /**
     * 单据设计 -- 新增引用属性
     * @param voucherReferenceVo
     */
    @Override
    public void addReferencePropertyField(VoucherReferenceVo voucherReferenceVo) {
        Integer currentAccountId = erpAccountService.getCurrentAccountId();
        if(null == currentAccountId)throw new NuoNiuException("当前账套已经结算或者没有账套");
        String referenceTableCode = voucherReferenceVo.getReferenceTableCode();
        ErpVoucherTable erpVoucherTable = erpVoucherTableService.getErpVoucherTable(referenceTableCode);


        String code = erpVoucherTable.getTableName() + '.' + voucherReferenceVo.getCode();
        boolean haveCode = isHaveCode(code,voucherReferenceVo.getDataTab());
        if(haveCode)throw new NuoNiuException("保存失败，该引用属性参数已经添加过了");
        LocalDateTime now = LocalDateTime.now();
        UserInfo userInfo = UserThreadLocal.get();

        ErpVoucherDesign erpVoucherDesign = new ErpVoucherDesign();

        erpVoucherDesign.setRelationField(voucherReferenceVo.getVoucherField());  // 设置主表关联字段
        erpVoucherDesign.setCode(code);
        String name = erpVoucherTable.getVoucherTypeName() + '.' + voucherReferenceVo.getName();
        erpVoucherDesign.setName(name);
        if(1 == voucherReferenceVo.getDataType()){
            erpVoucherDesign.setDataType(3);
        }else if(2 == voucherReferenceVo.getDataType()){
            erpVoucherDesign.setDataType(4);
        }else{
            return;
        }
        erpVoucherDesign.setReferenceDesignId(voucherReferenceVo.getVoucherDesignId());
        erpVoucherDesign.setColumnType(voucherReferenceVo.getColumnType());
        erpVoucherDesign.setSource(voucherReferenceVo.getVoucherCode());
        erpVoucherDesign.setDataTab(voucherReferenceVo.getDataTab());

        erpVoucherDesign.setAccountId(currentAccountId);
        erpVoucherDesign.setSysName(erpVoucherDesign.getName());
        erpVoucherDesign.setCompanyId(userInfo.getCompanyId());
        erpVoucherDesign.setCompanyName((userInfo.getCompanyName()));
        erpVoucherDesign.setCreateDate(now);
        erpVoucherDesign.setCreateUserId(userInfo.getUserId());
        erpVoucherDesign.setCreateUserName(userInfo.getRealName());
        save(erpVoucherDesign);


    }

    @Override
    public boolean isHaveCode(String code, String dataTab) {
        if(StringUtils.isBlank(code))throw new NuoNiuException("编码不能为空");
        QueryWrapper<ErpVoucherDesign> queryWrapper = new QueryWrapper<>();
        if("表头".equals(dataTab)){
            queryWrapper.in("data_tab","表头","表尾");
        }else if("明细".equals(dataTab)){
            queryWrapper.in("data_tab",dataTab);
        }else{
            throw new NuoNiuException("参数错误");
        }
        queryWrapper.eq("code",code);
        int count = count(queryWrapper);
        return count > 0;
    }


    @Override
    public void batchUpdate(List<ErpVoucherDesignDto> erpDocumentDesignDtos) {
        List<ErpVoucherDesign> currentErpVoucherDesigns = new ArrayList<>();
        if(erpDocumentDesignDtos.size() > 0){
            ErpVoucherDesignDto erpVoucherDesignDto = erpDocumentDesignDtos.get(0);
            String source = erpVoucherDesignDto.getSource();
            ErpVoucherDesignSearchDto erpVoucherDesignSearchDto = new ErpVoucherDesignSearchDto();
            erpVoucherDesignSearchDto.setSource(source);
            currentErpVoucherDesigns = getCurrentErpVoucherDesign(erpVoucherDesignSearchDto);
        }
        if(currentErpVoucherDesigns.size() == 0)throw new NuoNiuException("保存失败，参数错误");
        List<ErpVoucherDesign> currentErpVoucherDesignList = currentErpVoucherDesigns;
        List<ErpVoucherDesign> submitList = new ArrayList<>();
        boolean isIdNull = erpDocumentDesignDtos.stream().anyMatch(f -> null == f.getId());
        if(isIdNull)throw new NuoNiuException("保存失败，参数错误");
        erpDocumentDesignDtos.forEach(dto->{
            Long dtoId = dto.getId();
            if (!currentErpVoucherDesignList.stream().anyMatch(f-> f.getId().equals(dtoId))){
                throw new NuoNiuException("保存失败，参数错误");
            }
            ErpVoucherDesign erpVoucherDesign = new ErpVoucherDesign();
            BeanUtils.copyProperties(dto,erpVoucherDesign);
            submitList.add(erpVoucherDesign);
        });
        if(submitList.size() > 0 ){
            saveOrUpdateBatch(submitList);
        }

    }


    @Override
    public List<ErpVoucherDesign> getCurrentErpVoucherDesign(ErpVoucherDesignSearchDto erpVoucherDesignSearchDto) {
        String source = erpVoucherDesignSearchDto.getSource();
        String name = erpVoucherDesignSearchDto.getName();
        String code = erpVoucherDesignSearchDto.getCode();
        UserInfo userInfo = UserThreadLocal.get();
        Integer currentAccountId = erpAccountService.getCurrentAccountId();
        if(null == currentAccountId)throw new NuoNiuException("当前账套已经结算或者没有账套");

        QueryWrapper<ErpVoucherDesign> erpVoucherDesignQueryWrapper = new QueryWrapper<>();
        erpVoucherDesignQueryWrapper.eq("company_id",userInfo.getCompanyId());
        erpVoucherDesignQueryWrapper.eq("source",source);
        erpVoucherDesignQueryWrapper.eq("status",0);
        erpVoucherDesignQueryWrapper.eq("account_id",currentAccountId);
        erpVoucherDesignQueryWrapper.orderByAsc("sort");
        if(StringUtils.isNotBlank(name)){
            erpVoucherDesignQueryWrapper.like("name",name);
        }
        if(StringUtils.isNotBlank(code)){
            erpVoucherDesignQueryWrapper.like("name",code);
        }
        List<ErpVoucherDesign> list = list(erpVoucherDesignQueryWrapper);
//        log.debug("获取单据设计{}：：{}",source,JSONObject.toJSONString(list));
        return list;
    }

    @Override
    public void deleteCustomField(Integer id) {
        Integer currentAccountId = erpAccountService.getCurrentAccountId();
        if(null == currentAccountId)throw new NuoNiuException("删除失败,参数错误");
        UserInfo userInfo = UserThreadLocal.get();
        if(null == id)throw new NuoNiuException("ID不能为空");
        ErpVoucherDesign erpVoucherDesign = getById(id);
        if(null == erpVoucherDesign)throw new NuoNiuException("参数错误");
        if(!currentAccountId.equals(erpVoucherDesign.getAccountId()))throw new NuoNiuException("删除失败,参数错误");
        ErpVoucherTable erpVoucherTable = erpVoucherTableService.getErpVoucherTable(erpVoucherDesign.getSource());
        if(null == erpVoucherTable)throw new NuoNiuException("参数错误");
        String tableName = erpVoucherTable.getTableName();
        if(StringUtils.isBlank(tableName))throw new NuoNiuException("参数错误");
        int number = baseMapper.countDefineFieldUsedNumber(tableName ,userInfo.getCompanyId(), id);
        if(number > 0)throw new NuoNiuException("删除失败,该字段已经使用,不能删除");
        int number2 = baseMapper.countReferenceFieldUsedNumber(userInfo.getCompanyId(), id);
        if(number2 > 0)throw new NuoNiuException("删除失败,该字段已经被引用,不能删除");

        removeById(id);
    }






    /**************************************** 超级管理员权限 ****************************************/
    /**
     * 系统超级管理员
     * @param source
     * @return
     */
    @Override
    public List<ErpVoucherDesign> getDefErpVoucherDesign(String source) {

        QueryWrapper<ErpVoucherDesign> erpVoucherDesignQueryWrapper = new QueryWrapper<>();
        erpVoucherDesignQueryWrapper.eq("company_id",1);
        erpVoucherDesignQueryWrapper.eq("account_id",0);
        if(StringUtils.isNotBlank(source)){
            erpVoucherDesignQueryWrapper.eq("source",source);
        }
        erpVoucherDesignQueryWrapper.ne("status",1);
        erpVoucherDesignQueryWrapper.orderByAsc("sort");
        List<ErpVoucherDesign> list = list(erpVoucherDesignQueryWrapper);
        return list;
    }

    @Override
    public void batchSystemUpdate(List<ErpVoucherDesignDto> erpDocumentDesignDtos) {

        List<ErpVoucherDesign> currentErpVoucherDesigns = new ArrayList<>();
        if(erpDocumentDesignDtos.size() > 0){
            ErpVoucherDesignDto erpVoucherDesignDto = erpDocumentDesignDtos.get(0);
            String source = erpVoucherDesignDto.getSource();
            currentErpVoucherDesigns = getDefErpVoucherDesign(source);
        }
        if(currentErpVoucherDesigns.size() == 0)throw new NuoNiuException("保存失败，参数错误");
        List<ErpVoucherDesign> currentErpVoucherDesignList = currentErpVoucherDesigns;
        List<ErpVoucherDesign> submitList = new ArrayList<>();
        boolean isIdNull = erpDocumentDesignDtos.stream().anyMatch(f -> null == f.getId());
        if(isIdNull)throw new NuoNiuException("保存失败，参数错误");
        erpDocumentDesignDtos.forEach(dto->{
            Long dtoId = dto.getId();
            if (!currentErpVoucherDesignList.stream().anyMatch(f-> f.getId().equals(dtoId))){
                throw new NuoNiuException("保存失败，参数错误");
            }
            ErpVoucherDesign erpVoucherDesign = new ErpVoucherDesign();
            BeanUtils.copyProperties(dto,erpVoucherDesign);
            submitList.add(erpVoucherDesign);
        });
        if(submitList.size() > 0 ){
            saveOrUpdateBatch(submitList);
        }

    }


    @Override
    public void deleteSystemField(Integer id) {
        updateSystemFieldStatus(id,1);
    }

    @Override
    public void enableSystemField(Integer id) {
        updateSystemFieldStatus(id,0);
    }

    @Override
    public void disableSystemField(Integer id) {
        updateSystemFieldStatus(id,2);
    }

    @Override
    public void updateSystemFieldStatus(Integer id, Integer status) {
        UserInfo userInfo = UserThreadLocal.get();
        UpdateWrapper<ErpVoucherDesign> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("company_id",userInfo.getCompanyId());
        updateWrapper.eq("account_id",0);
        updateWrapper.eq("id",id);
        updateWrapper.set("status",status);
        boolean update = update(updateWrapper);
        if(!update){
            throw new NuoNiuException("更新状态失败");
        }
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void lockField(ErpVoucherDesignDto erpVoucherDesignDto) {
        Long id = erpVoucherDesignDto.getId();
        if(null == id)throw new NuoNiuException("锁定失败，ID不能为空");
        ErpVoucherDesign voucherDesign = getById(id);
        if(null == voucherDesign)throw new NuoNiuException("锁定失败，ID参数错误");
        Integer accountId = voucherDesign.getAccountId();
        Integer companyId = voucherDesign.getCompanyId();
        if(!(1 == companyId && 0 == accountId))throw new NuoNiuException("锁定失败，参数错误");
        BeanUtils.copyProperties(erpVoucherDesignDto,voucherDesign);
        voucherDesign.setOnLocked(true);
        //保存当前 被锁定 系统字段的 属性
        boolean b = updateById(voucherDesign);
        if(b){
            //更新 租户的 字段
            baseMapper.batchUpdateCompanyErpVoucherDesign(voucherDesign);
        }

    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void unLockField(Integer id) {
        if(null == id)throw new NuoNiuException("解锁失败，ID不能为空");
        ErpVoucherDesign voucherDesign = getById(id);
        if(null == voucherDesign)throw new NuoNiuException("解锁失败，ID参数错误");
        Integer accountId = voucherDesign.getAccountId();
        Integer companyId = voucherDesign.getCompanyId();
        if(!(1 == companyId && 0 == accountId))throw new NuoNiuException("解锁失败，参数错误");
        voucherDesign.setOnLocked(false);
        //保存当前 被锁定 系统字段的 属性
        boolean b = updateById(voucherDesign);
        if(b){
            //更新 租户的 字段
            baseMapper.batchUpdateCompanyErpVoucherDesign(voucherDesign);
        }
    }

    @Override
    public List<VoucherReferenceVo> listByReferenceTableCode(String voucherCode) {
        UserInfo userInfo = UserThreadLocal.get();
        Integer currentAccountId = erpAccountService.getCurrentAccountId();
        List<VoucherReferenceVo>  list = baseMapper.listByReferenceTableCode(userInfo.getCompanyId(),currentAccountId,voucherCode);
        return list;
    }



    /**
     * 转换T+ 单据设置 字段
     */
    public void initDataFromSqlServer(){

    }

    @Override
    @Async
    public void ansyncFun(List<ErpVoucherType> erpVoucherTypeList) {

        erpVoucherTypeList.forEach(erpVoucherType -> {
            List<ErpVoucherDesign> erpVoucherDesignList = new ArrayList<>();
            String voucherCode = erpVoucherType.getVoucherCode();
            log.info("单据Code：{}",voucherCode);
            List<LinkedHashMap<String, Object>> tableColumnList = listTableColumns(voucherCode);
            List<LinkedHashMap<String, Object>> tabControlList = listTabControls(voucherCode);
            tableColumnToErpVoucherDesign(tableColumnList,erpVoucherDesignList,voucherCode);
            tabControlToErpVoucherDesign(tabControlList,erpVoucherDesignList,voucherCode);
            //保存
            if(erpVoucherDesignList.size() > 0){
                saveBatch(erpVoucherDesignList);
                log.info("批量保存：单据Code：{}",voucherCode);
            }

        });
    }


    public void tableColumnToErpVoucherDesign(List<LinkedHashMap<String, Object>> tableColumnList,List<ErpVoucherDesign> erpVoucherDesignList,String voucherCode){
        tableColumnList.forEach(colum->{

            Object name = colum.get("Name");                            //字段Code
            Object tableTitle = colum.get("tableTitle");                //页签
            Object Title = colum.get("Title");                          //当前字段名称
            Object OriginalTitle = colum.get("OriginalTitle");          //系统字段名称
            Object FieldType = colum.get("FieldType");                  //字段类型（Decimal、Bool、String）
            Object ColumnType = colum.get("ColumnType");                //控件类型 （TextBox、CheckBox、RefComboBox、NumTextBox）
            Object Visible = colum.get("Visible");                      //是否 显示（是否启用）
            Object AllowNull = colum.get("AllowNull");                  //是否为空（是否必填）
            Object ReadOnly = colum.get("ReadOnly");                    //是否只读（是否可改）
            Object AllowUserDef = colum.get("AllowUserDef");            //是否允许用户设置
            Object ShowSysField = colum.get("ShowSysField");            //是否系统字段
            Object AllowTotal = colum.get("AllowTotal");                //是否可以汇总

            ErpVoucherDesign erpVoucherDesign = new ErpVoucherDesign();
            erpVoucherDesign.setCompanyId(1);
            erpVoucherDesign.setCompanyName("重庆诺牛科技有限公司");
            erpVoucherDesign.setSource(voucherCode);
            erpVoucherDesign.setCode(null != name ? name.toString():"");
            erpVoucherDesign.setDataTab(null != tableTitle ? tableTitle.toString():"");
            erpVoucherDesign.setName(null != Title ? Title.toString():"");
            erpVoucherDesign.setSysName(null != OriginalTitle ? OriginalTitle.toString():"");
            String myColumnType = "文本";
            if(null != ColumnType ){
                switch (ColumnType.toString()){
                    case "TextBox" : myColumnType = "文本";break;
                    case "CheckBox" : myColumnType = "复选";break;
                    case "NumTextBox" : myColumnType = "小数";break;
                    case "RefComboBox" : myColumnType = "搜索选择";break;
                }
            }
            erpVoucherDesign.setColumnType(myColumnType);


            erpVoucherDesign.setOnOff(null != Visible ? Boolean.valueOf(Visible.toString()) : false);
            erpVoucherDesign.setOnFill(null != AllowNull ? Boolean.valueOf(AllowNull.toString()) : false);
            erpVoucherDesign.setOnEdit(null != ReadOnly ? !Boolean.valueOf(ReadOnly.toString()) : false);
            erpVoucherDesign.setOnLocked(null != AllowUserDef ? !Boolean.valueOf(AllowUserDef.toString()) : false);
            erpVoucherDesign.setIsSummary(null != AllowTotal ? Boolean.valueOf(AllowTotal.toString()) : false);
            erpVoucherDesign.setDataType(null != ShowSysField ? Boolean.valueOf(ShowSysField.toString()) ? 1 : 2 : 2);
            erpVoucherDesignList.add(erpVoucherDesign);

        });


    }

    public void tabControlToErpVoucherDesign(List<LinkedHashMap<String, Object>> tabControlList,List<ErpVoucherDesign> erpVoucherDesignList,String voucherCode){

        tabControlList.forEach(colum->{
            Object name = colum.get("Name");                            //字段Code
            Object tableTitle = colum.get("tabTitle");                //页签
            Object Title = colum.get("Title");                          //当前字段名称
            Object OriginalTitle = colum.get("OriginalTitle");          //系统字段名称
            Object FieldType = colum.get("FieldType");                  //字段类型（Decimal、Bool、String）
            Object ColumnType = colum.get("ColumnType");                //控件类型 （TextBox、CheckBox、RefComboBox、NumTextBox）
            Object Visible = colum.get("Visible");                      //是否 显示（是否启用）
            Object AllowNull = colum.get("AllowNull");                  //是否为空（是否必填）
            Object ReadOnly = colum.get("EditReadOnly");                    //是否只读（是否可改）
            Object AllowUserDef = colum.get("AllowUserDef");            //是否允许用户设置
            Object ShowSysField = colum.get("ShowSysField");            //是否系统字段

            ErpVoucherDesign erpVoucherDesign = new ErpVoucherDesign();
            erpVoucherDesign.setCompanyId(1);
            erpVoucherDesign.setCompanyName("重庆诺牛科技有限公司");
            erpVoucherDesign.setSource(voucherCode);
            erpVoucherDesign.setCode(null != name ? name.toString():"");
            erpVoucherDesign.setDataTab(null != tableTitle ? tableTitle.toString():"");
            erpVoucherDesign.setName(null != Title ? Title.toString():"");
            erpVoucherDesign.setSysName(null != OriginalTitle ? OriginalTitle.toString():"");
            String myColumnType = "文本";
            if(null != ColumnType ){
                switch (ColumnType.toString()){
                    case "TextBox" : myColumnType = "文本";break;
                    case "CheckBox" : myColumnType = "复选";break;
                    case "NumTextBox" : myColumnType = "小数";break;
                    case "RefComboBox" : myColumnType = "搜索选择";break;
                }
            }
            erpVoucherDesign.setColumnType(myColumnType);


            erpVoucherDesign.setOnOff(null != Visible ? Boolean.valueOf(Visible.toString()) : false);
            erpVoucherDesign.setOnFill(null != AllowNull ? Boolean.valueOf(AllowNull.toString()) : false);
            erpVoucherDesign.setOnEdit(null != ReadOnly ? !Boolean.valueOf(ReadOnly.toString()) : false);
            erpVoucherDesign.setOnLocked(null != AllowUserDef ? !Boolean.valueOf(AllowUserDef.toString()) : false);
            erpVoucherDesign.setDataType(null != ShowSysField ? Boolean.valueOf(ShowSysField.toString()) ? 1 : 2 : 2);

            erpVoucherDesignList.add(erpVoucherDesign);

        });


    }

    /**
     * 1.单据明细/汇总 字段
     * @param name
     * @return
     */
    public  List<LinkedHashMap<String,Object>> listTableColumns(String name) {
        RestTemplate restTemplate=new RestTemplate();
        Map<String,String> params=new HashMap<>();
        params.put("name",name);  //
        ResponseEntity<List> responseEntity=restTemplate.getForEntity("http://192.168.1.131:9001/a/customerManage/crmCompany/listTableColumns?name={name}",List.class,params);
        List body = responseEntity.getBody();
        return body;
    }

    /**
     * 2.单据页签 字段
     * @param name
     * @return
     */
    public  List<LinkedHashMap<String,Object>> listTabControls(String name) {
        RestTemplate restTemplate=new RestTemplate();
        Map<String,String> params=new HashMap<>();
        params.put("name",name);  //
        ResponseEntity<List> responseEntity=restTemplate.getForEntity("http://192.168.1.131:9001/a/customerManage/crmCompany/listTabControls?name={name}",List.class,params);
        List body = responseEntity.getBody();
        return body;
    }







}
